home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
vsc92nov.zip
/
Code.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-02
|
33KB
|
1,285 lines
/*
* Code.c -- Implementation of Scheme Bytecode
*
* (C) m.b (Matthias Blume), Apr 1992, HUB/Ger
*/
# ident "@(#)Code.c (C) M.Blume, Humboldt-Uni Berlin, 1.10"
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <assert.h>
# include <setjmp.h>
# include "storext.h"
# include "Code.h"
# include "Cont.h"
# include "Symbol.h"
# include "String.h"
# include "Cons.h"
# include "Boolean.h"
# include "Procedure.h"
# include "Promise.h"
# include "Primitive.h"
# include "Number.h"
# include "identifier.h"
# include "type.h"
# include "except.h"
# include "keyword.h"
# include "speccont.h"
# include "mode.h"
/*
* This is a description of the Scheme Bytecode statements:
*
* Note: All jump instructions except JUMP_BACK jump FORWARD.
*
* The statements:
*
* 1. Access to variables:
* GET_LOC <index> -- local (impl. PUSH)
* GET_ENV <frameno> <index> -- distant (impl. PUSH)
* GET_GLOB <symbol> -- global (impl. PUSH)
* 2. Set variable's value:
* PUT_LOC <index> -- local (*NO* POP)
* PUT_ENV <frameno> <index> -- distant (*NO* POP)
* PUT_GLOB <symbol> -- global (*NO* POP)
* PUT_LOC_POP <index> -- local (impl. POP)
* PUT_ENV_POP <frameno> <index> -- distant (impl. POP)
* PUT_GLOB_POP <symbol> -- global (impl. POP)
* 3. extend/reset environment
* FRAME <size> <vector>
* FILL_FRAME <size> <vector>
* POP_FRAME
* 4. Constants
* TAKE <constant> -- (impl. PUSH)
* 5. Pop one stack element
* POP
* 6. Combinations
* CALL <argcnt>
* CALL_AND_EXIT <argcnt>
* EXIT
* 7. Conditionals (if's and "normal" cond's) and Loops
* POP_JUMP_IF_FALSE <distance> -- POPs always
* POP_JUMP_IF_TRUE <distance> -- POPs always
* JUMP_IF_FALSE_ELSE_POP <distance> -- POPs only, when true
* JUMP <distance>
* JUMP_BACK <distance>
* 8. (cond (<something>) ...)
* JUMP_IF_TRUE_ELSE_POP <distance> -- POPs only, when false
* 9. (cond (<something> => <func>) ...)
* JUMP_IF_FALSE_POP <distance> -- POPs only, when false
* 10. (lambda <formals> <body>)
* LAMBDA <code>
* 11. (delay <expression>)
* DELAY <code> -- like LAMBDA
* 12. (case <item> ((...) ...) ...)
* JUMP_IF_NOT_MEMV <distance> <list> -- POPs only, when memv
* 13. Miscellaneous (for quasiquote):
* CONS
* APPEND
* -- both statements imply two times POP and one PUSH
* LIST_TO_VECTOR -- one POP, one PUSH
* VECTOR <cnt> -- <cnt> POP's
* 14. Pushing special values
* TAKE_TRUE
* TAKE_FALSE
* TAKE_NIL
*/
/*
* The next section defines OP-Codes for the Scheme Bytecode Statements:
*/
# define GET_LOC 0x00
# define GET_ENV 0x01
# define GET_GLOB 0x02
# define PUT_LOC 0x03
# define PUT_ENV 0x04
# define PUT_GLOB 0x05
# define PUT_LOC_POP 0x06
# define PUT_ENV_POP 0x07
# define PUT_GLOB_POP 0x08
# define FRAME 0x09
# define FILL_FRAME 0x0a
# define POP_FRAME 0x0b
# define TAKE 0x0c
# define POP 0x0d
# define CALL 0x0e
# define CALL_AND_EXIT 0x0f
# define EXIT 0x10
# define JUMP 0x11
# define JUMP_BACK 0x12
# define POP_JUMP_IF_FALSE 0x13
# define POP_JUMP_IF_TRUE 0x14
# define JUMP_IF_FALSE_ELSE_POP 0x15
# define JUMP_IF_TRUE_ELSE_POP 0x16
# define JUMP_IF_FALSE_POP 0x17
# define JUMP_IF_TRUE_POP 0x18
# define LAMBDA 0x19
# define DELAY 0x1a
# define JUMP_IF_NOT_MEMV 0x1b
# define CONS 0x1c
# define APPEND 0x1d
# define LIST_TO_VECTOR 0x1e
# define VECTOR 0x1f
# define TAKE_TRUE 0x20
# define TAKE_FALSE 0x21
# define TAKE_NIL 0x22
# define GET_LOC_len (1 + 1)
# define GET_ENV_len (1 + 2 * 1)
# define GET_GLOB_len (1 + 1)
# define PUT_LOC_len (1 + 1)
# define PUT_ENV_len (1 + 2 * 1)
# define PUT_GLOB_len (1 + 1)
# define PUT_LOC_POP_len (1 + 1)
# define PUT_ENV_POP_len (1 + 2 * 1)
# define PUT_GLOB_POP_len (1 + 1)
# define FRAME_len (1 + 2 * 1)
# define FILL_FRAME_len (1 + 2 * 1)
# define POP_FRAME_len (1)
# define TAKE_len (1 + 1)
# define POP_len (1)
# define CALL_len (1 + 1)
# define CALL_AND_EXIT_len (1 + 1)
# define EXIT_len (1)
# define JUMP_len (1 + 1)
# define JUMP_BACK_len (1 + 1)
# define POP_JUMP_IF_FALSE_len (1 + 1)
# define POP_JUMP_IF_TRUE_len (1 + 1)
# define JUMP_IF_FALSE_ELSE_POP_len (1 + 1)
# define JUMP_IF_TRUE_ELSE_POP_len (1 + 1)
# define JUMP_IF_FALSE_POP_len (1 + 1)
# define JUMP_IF_TRUE_POP_len (1 + 1)
# define LAMBDA_len (1 + 1)
# define DELAY_len (1 + 1)
# define JUMP_IF_NOT_MEMV_len (1 + 2 * 1)
# define CONS_len (1)
# define APPEND_len (1)
# define LIST_TO_VECTOR_len (1)
# define VECTOR_len (1 + 1)
# define TAKE_TRUE_len (1)
# define TAKE_FALSE_len (1)
# define TAKE_NIL_len (1)
static
struct stat_desc {
unsigned short opcode;
int length;
const char *name;
} stat_desc [0x23] = {
/* alphabetically ordered.... */
{ APPEND, APPEND_len, "append" },
{ CALL, CALL_len, "call" },
{ CALL_AND_EXIT, CALL_AND_EXIT_len, "call-and-exit" },
{ CONS, CONS_len, "cons" },
{ DELAY, DELAY_len, "delay" },
{ EXIT, EXIT_len, "exit" },
{ FILL_FRAME, FILL_FRAME_len, "fill-frame" },
{ FRAME, FRAME_len, "frame" },
{ GET_ENV, GET_ENV_len, "get-env" },
{ GET_GLOB, GET_GLOB_len, "get-glob" },
{ GET_LOC, GET_LOC_len, "get-loc" },
{ JUMP, JUMP_len, "jump" },
{ JUMP_BACK, JUMP_BACK_len, "jump-back" },
{ JUMP_IF_FALSE_ELSE_POP, JUMP_IF_FALSE_ELSE_POP_len,
"jump-if-false-else-pop" },
{ JUMP_IF_FALSE_POP, JUMP_IF_FALSE_POP_len, "jump-if-false-pop" },
{ JUMP_IF_NOT_MEMV, JUMP_IF_NOT_MEMV_len, "jump-if-not-memv" },
{ JUMP_IF_TRUE_ELSE_POP, JUMP_IF_TRUE_ELSE_POP_len, "jump-if-true-else-pop" },
{ JUMP_IF_TRUE_POP, JUMP_IF_TRUE_POP_len, "jump-if-true-pop" },
{ LAMBDA, LAMBDA_len, "lambda" },
{ LIST_TO_VECTOR, LIST_TO_VECTOR_len, "list->vector" },
{ POP, POP_len, "pop" },
{ POP_FRAME, POP_FRAME_len, "pop-frame" },
{ POP_JUMP_IF_FALSE, POP_JUMP_IF_FALSE_len, "pop-jump-if-false" },
{ POP_JUMP_IF_TRUE, POP_JUMP_IF_TRUE_len, "pop-jump-if-true" },
{ PUT_ENV, PUT_ENV_len, "put-env" },
{ PUT_ENV_POP, PUT_ENV_POP_len, "put-env-pop" },
{ PUT_GLOB, PUT_GLOB_len, "put-glob" },
{ PUT_GLOB_POP, PUT_GLOB_POP_len, "put-glob-pop" },
{ PUT_LOC, PUT_LOC_len, "put-loc" },
{ PUT_LOC_POP, PUT_LOC_POP_len, "put-loc-pop" },
{ TAKE, TAKE_len, "take" },
{ TAKE_FALSE, TAKE_FALSE_len, "take-false" },
{ TAKE_NIL, TAKE_NIL_len, "take-nil" },
{ TAKE_TRUE, TAKE_TRUE_len, "take-true" },
{ VECTOR, VECTOR_len, "vector" },
};
# ifdef VM_INSTRUCTION_COUNTING
static unsigned long vm_counts [0x23];
# define COUNT(x) (vm_counts [x]++)
static void vm_statistics (void)
{
int i;
for (i = 0; i < (sizeof stat_desc / sizeof stat_desc[0]); i++)
fprintf (stderr, "\t*\t%10lu\t%s\n",
vm_counts [stat_desc [i].opcode],
stat_desc [i].name);
}
# else
# define COUNT(x) ((void)0)
# endif
static
struct stat_desc *find_stat (const char *name, unsigned short len)
{
int start = 0;
int stop = sizeof stat_desc / sizeof (struct stat_desc) - 1;
int m, cmp, llen;
while (start <= stop) {
m = (start + stop) / 2;
cmp = strncmp (name, stat_desc [m].name, len);
if (cmp == 0) {
llen = strlen (stat_desc [m].name);
if (llen == len)
return stat_desc + m;
else
cmp = -1;
}
if (cmp < 0)
stop = m - 1;
else
start = m + 1;
}
error ("vscm-asm: bad operation code");
/*NOTREACHED*/
}
/*
* And now the normal stuff needed by type management:
*/
static
size_t size_hook (void *vcode)
{
return (sizeof (ScmCode) +
(((ScmCode *)vcode)->length - 1) * sizeof (unsigned short));
}
static
void apply_to_subs (void *vcode, applied_proc proc, void *cd)
{
ScmCode *code = vcode;
(* proc) ((void *)&code->argument_names, cd);
(* proc) ((void *)&code->constants, cd);
(* proc) ((void *)&code->proc_name, cd);
}
static
void dump (void *vcode, FILE *file)
{
ScmCode *code = (ScmCode *) vcode;
unsigned i;
fprintf (file, "%uX%c",
(unsigned int) (code->arg_cnt),
code->take_rest ? 'y' : 'n');
dump_ul (code->stack_requirement, file);
dump_ul (code->length, file);
i = 0;
while(i < code->length) {
dump_ul (code->array [i], file);
i++;
}
}
static
void *restore_init (FILE *file)
{
ScmCode *code;
unsigned i;
unsigned short length, arg_cnt, stack_requirement;
unsigned char c;
if (fscanf (file, "%huX%c",
&arg_cnt, &c) < 2)
fatal ("bad dump file format (Code)");
stack_requirement = restore_ul (file);
length = restore_ul (file);
code = getmem (ScmType (Code),
sizeof (ScmCode) + (length - 1) * sizeof (unsigned short));
code->arg_cnt = arg_cnt;
code->stack_requirement = stack_requirement;
code->length = length;
code->take_rest = (c == 'y');
i = 0;
while(i < length) {
code->array [i] = restore_ul (file);
i++;
}
return code;
}
static
void display (void *vcode, putc_proc pp, void *cd)
{
char buf [32];
ScmCode *code = vcode;
sprintf (buf, "#<Code %p ", vcode);
putc_string (buf, pp, cd);
display_object (code->proc_name, pp, cd);
sprintf (buf, " %u%s>", (unsigned) code->arg_cnt,
code->take_rest ? "+" : "");
putc_string (buf, pp, cd);
}
static void *reverse_old = NULL;
static void *reverse_new = NULL;
static void *append_save = NULL;
static void *constants_save = NULL;
static ScmProcedure *proc_save = NULL;
# define MAX_INTERRUPTS 16 /* this should be enough */
static unsigned pending_interrupts = 0;
static struct {
void *vect;
unsigned short cont;
} int_table [MAX_INTERRUPTS];
static void appl_int_table (void *tab, applied_proc proc, void *cd)
{
int i;
for (i = 0; i < MAX_INTERRUPTS; i++)
(* proc) ((void *)&int_table[i].vect, cd);
}
static
void module_init (void)
{
register_global_variable (reverse_old);
register_global_variable (reverse_new);
register_global_variable (append_save);
register_global_variable (constants_save);
register_global_variable (proc_save);
register_global_object (int_table, appl_int_table);
}
static
struct scheme_od_extension ext = {
display, display,
NULL, NULL, /* Note: bytecode should never be compared to anything*/
};
OD_VECTOR (ScmCode_od_vector,
0,
size_hook,
apply_to_subs,
CODE_IDENTIFIER,
dump, restore_init, NULL,
module_init,
NULL, NULL,
&ext
);
/*
* The interpreter (code emulator)
*/
static void *ScmMemv (void *item, void *list)
{
while (ScmTypeOf (list) == ScmType (Cons))
if (eqv_object (((ScmCons *) list)->car, item))
return list;
else
list = ((ScmCons *) list)->cdr;
return &ScmFalse;
}
unsigned long ScmListLength (void *l)
{
unsigned long i;
i = 0;
while (ScmTypeOf (l) == ScmType (Cons))
l = ((ScmCons *) l)->cdr,
i++;
return i;
}
void *ScmReverseList (void *l)
{
ScmCons *cons;
void *r;
unsigned long len, i;
len = ScmListLength (l);
if (len == 0)
return &ScmNil;
reverse_old = l;
cons = getmem (NULL, len * sizeof (ScmCons));
r = reverse_old;
reverse_old = NULL;
for (i = len; i-- > 0; ) {
cons [i]._ = ScmType (Cons);
cons [i].car = ((ScmCons *) r)->car;
r = ((ScmCons *) r)->cdr;
cons [i].cdr = cons + i + 1;
}
cons [len - 1].cdr = &ScmNil;
return cons;
}
void *ScmReverseIP2 (void *l, void *r)
{
ScmCons *tmp;
while (ScmTypeOf (l) == ScmType (Cons)) {
tmp = l;
l = tmp->cdr;
tmp->cdr = r;
r = tmp;
}
return r;
}
void *ScmAppendTwoLists (void *l1, void *l2)
{
ScmCons *cons;
unsigned long len, i;
void *r;
len = ScmListLength (l1);
if (len == 0)
return l2;
reverse_old = l1;
append_save = l2;
cons = getmem (NULL, len * sizeof (ScmCons));
l2 = append_save;
r = reverse_old;
append_save = reverse_old = NULL;
for (i = 0; i < len; i++) {
cons [i]._ = ScmType (Cons);
cons [i].car = ((ScmCons *) r)->car;
r = ((ScmCons *) r)->cdr;
cons [i].cdr = cons + i + 1;
}
cons [len - 1].cdr = l2;
return cons;
}
void ScmListToVector (void)
{
ScmCons *l;
unsigned long len, i;
ScmVector *vect;
vect = NewScmVector (len = ScmListLength (ScmPeek ()));
l = ScmPeek ();
for (i = 0; i < len; i++) {
vect->array [i] = l->car;
l = l->cdr;
}
ScmSetTop (vect);
}
void ScmPrepareProcedureCall (void *vproc, unsigned short argcnt)
{
ScmVector *vect;
unsigned i, j, siz;
ScmCons *cons;
proc_save = vproc;
ScmPushContinuation (((ScmCode *) proc_save->code)->stack_requirement);
ScmCC.code = proc_save->code;
ScmCC.constants = ScmCC.code->constants;
siz = ScmCC.code->arg_cnt + (ScmCC.code->take_rest ? 1 : 0);
if (siz > 0) {
vect = NewScmVector (siz + 2);
ScmCC.environ = vect;
vect->array [0] = proc_save->env;
vect->array [1] = ScmCC.code->argument_names;
siz = ScmCC.code->arg_cnt;
if (siz > argcnt)
error ("too few arguments to procedure %w", proc_save);
for (i = 0; i < siz; i++)
vect->array [i + 2] = ScmCPop (ScmCC.father);
if (ScmCC.code->take_rest) {
if (i >= argcnt)
vect->array [i + 2] = &ScmNil;
else {
cons = getmem (NULL, (argcnt - i) * sizeof (ScmCons));
for (j = i; j < argcnt; j++) {
cons [j - i]._ = ScmType (Cons);
cons [j - i].car = ScmCPop (ScmCC.father);
cons [j - i].cdr = cons + j - i + 1;
}
cons [argcnt - i - 1].cdr = &ScmNil;
vect = ScmCC.environ;
vect->array [i + 2] = cons;
}
} else
if (i < argcnt)
error ("too many arguments to procedure %w", proc_save);
} else {
ScmCC.environ = proc_save->env;
if (argcnt != 0)
error ("too many arguments to procedure %w", proc_save);
}
proc_save = NULL;
}
static unsigned short active_primitive = SCM_VM_TRAP_CONT;
static some_interrupt_pending = 0;
void ScmRegisterInterrupt (unsigned short cont, void *vvect)
{
some_interrupt_pending = 1;
if (pending_interrupts >= MAX_INTERRUPTS)
reset ("too many pending interrupts");
int_table [pending_interrupts].vect = vvect;
int_table [pending_interrupts].cont = cont;
pending_interrupts++;
}
static void handle_interrupts (void)
{
ScmVector *vect;
void *tmp;
unsigned i, j;
for (i = 0; i < pending_interrupts; i++) {
active_primitive = int_table [i].cont;
vect = int_table [i].vect;
ScmPushPrimitiveContinuation (vect, vect->length - 1);
active_primitive = SCM_VM_TRAP_CONT;
vect = ScmCC.environ;
for (j = vect->length - 1; j > 0; j--) {
tmp = vect->array [j];
ScmPush (tmp);
vect = ScmCC.environ;
}
int_table [i].vect = NULL;
ScmPrepareProcedureCall (vect->array [0], vect->length - 1);
}
pending_interrupts = 0;
}
static int asyn_interrupt = 0;
static int instant_interrupt_handling = 0;
static int memorized_instant_interrupt_handling;
static jmp_buf reactivation_point;
void ScmInstantInterruptHandling (int state)
{
instant_interrupt_handling = state;
}
void announce_gc_start (void)
{
memorized_instant_interrupt_handling = instant_interrupt_handling;
instant_interrupt_handling = 0;
}
void announce_gc_end (void)
{
instant_interrupt_handling = memorized_instant_interrupt_handling;
}
void ScmRegisterAsynInterrupt (void)
{
some_interrupt_pending = 1;
asyn_interrupt = 1;
if (instant_interrupt_handling) {
instant_interrupt_handling = 0;
ScmPush (&ScmEof);
longjmp (reactivation_point, 1);
}
}
static void handle_asyn_interrupt (void)
{
void *intmode = ScmMode (SCM_INTERRUPT_MODE);
asyn_interrupt = 0;
if (intmode == NULL)
reset ("Interrupt");
else {
active_primitive = SCM_VM_INTERRUPT_CONT;
ScmPushPrimitiveContinuation (intmode, 0);
active_primitive = SCM_VM_TRAP_CONT;
ScmPrepareProcedureCall (ScmCC.environ, 0);
}
}
/*
* Note: environment frames are implemented as plain ScmVectors using the
* the following convention:
* - env->array [0] always points back to the father frame
* - env->array [1] points to the environment description
* - env->array [2-] is the actual frame
*/
volatile void ScmVM (void)
{
unsigned const short *cp;
unsigned short index, frameno, con, siz, dist;
ScmVector *env_frame, *vect;
ScmPromise *prom;
ScmProcedure *proc;
ScmCons *cons;
void *tmp;
unsigned short argcnt;
# ifdef VM_INSTRUCTION_COUNTING
atexit (vm_statistics);
# endif
setjmp (reactivation_point);
/* loop forever */
for (;;) {
if (some_interrupt_pending) {
some_interrupt_pending = 0;
if (asyn_interrupt)
handle_asyn_interrupt ();
if (pending_interrupts > 0)
handle_interrupts ();
}
cp = ScmCC.code->array + ScmCC.nxt_stat;
COUNT(cp[0]);
switch (cp [0]) {
case GET_LOC:
index = cp [1];
ScmPush (((ScmVector *) (ScmCC.environ))->array [index + 2]);
ScmCC.nxt_stat += GET_LOC_len;
break;
case GET_ENV:
frameno = cp [1];
index = cp [2];
for (env_frame = ScmCC.environ;
frameno-- > 0;
env_frame = env_frame->array [0]);
ScmPush (env_frame->array [index + 2]);
ScmCC.nxt_stat += GET_ENV_len;
break;
case GET_GLOB:
con = cp [1];
tmp = ((ScmSymbol *) (ScmCC.constants->array [con]))->value;
if (tmp == NULL)
error ("Unbound variable: %w", ScmCC.constants->array [con]);
ScmPush (tmp);
ScmCC.nxt_stat += GET_GLOB_len;
break;
case PUT_LOC:
index = cp [1];
((ScmVector *) (ScmCC.environ))->array [index + 2] = ScmPeek ();
ScmCC.nxt_stat += PUT_LOC_len;
break;
case PUT_ENV:
frameno = cp [1];
index = cp [2];
for (env_frame = ScmCC.environ;
frameno-- > 0;
env_frame = env_frame->array [0]);
env_frame->array [index + 2] = ScmPeek ();
ScmCC.nxt_stat += PUT_ENV_len;
break;
case PUT_GLOB:
con = cp [1];
((ScmSymbol *) (ScmCC.constants->array [con]))->value = ScmPeek ();
ScmCC.nxt_stat += PUT_GLOB_len;
break;
case PUT_LOC_POP:
index = cp [1];
((ScmVector *) (ScmCC.environ))->array [index + 2] = ScmPop ();
ScmCC.nxt_stat += PUT_LOC_POP_len;
break;
case PUT_ENV_POP:
frameno = cp [1];
index = cp [2];
for (env_frame = ScmCC.environ;
frameno-- > 0;
env_frame = env_frame->array [0]);
env_frame->array [index + 2] = ScmPop ();
ScmCC.nxt_stat += PUT_ENV_POP_len;
break;
case PUT_GLOB_POP:
con = cp [1];
((ScmSymbol *) (ScmCC.constants->array [con]))->value
= ScmPop ();
ScmCC.nxt_stat += PUT_GLOB_POP_len;
break;
case FRAME:
siz = cp [1];
con = cp [2];
env_frame = NewScmVector (siz + 2);
env_frame->array [0] = ScmCC.environ;
env_frame->array [1] = ScmCC.constants->array [con];
ScmCC.environ = env_frame;
ScmCC.nxt_stat += FRAME_len;
break;
case FILL_FRAME:
siz = cp [1];
con = cp [2];
env_frame = NewScmVector (siz + 2);
env_frame->array [0] = ScmCC.environ;
env_frame->array [1] = ScmCC.constants->array [con];
ScmCC.environ = env_frame;
while (siz-- > 0)
env_frame->array [siz + 2] = ScmPop ();
ScmCC.nxt_stat += FILL_FRAME_len;
break;
case POP_FRAME:
ScmCC.environ = ((ScmVector *) (ScmCC.environ))->array [0];
ScmCC.nxt_stat += POP_FRAME_len;
break;
case TAKE:
con = cp [1];
ScmPush (ScmCC.constants->array [con]);
ScmCC.nxt_stat += TAKE_len;
break;
case POP:
(void) ScmPop ();
ScmCC.nxt_stat += POP_len;
break;
case CALL:
argcnt = cp [1];
ScmCC.nxt_stat += CALL_len;
# ifdef DEBUG
{
int i;
warning ("DEBUG: Calling :");
for (i = 0; i <= argcnt; i++)
warning(" %w", ScmCC.stack->array[ScmCC.stack_top - 1 - i]);
}
# endif
call_entry_point:
tmp = ScmPop ();
if (ScmTypeOf (tmp) == ScmType (Procedure)) {
ScmPrepareProcedureCall (tmp, argcnt);
} else if (ScmTypeOf (tmp) == ScmType (Primitive)) {
ScmPrimitive *prim = tmp;
if (prim->expected_argcnt >= 0 && prim->expected_argcnt != argcnt)
error ("wrong argcnt to primitive procedure %w", prim);
active_primitive = prim->seq_num;
(* prim->code) (argcnt);
active_primitive = SCM_VM_TRAP_CONT;
if (ScmCC.call_again > 0) {
argcnt = ScmCC.call_again - 1;
ScmCC.call_again = 0;
/* is there any chance to conveniently express this without goto ? */
goto call_entry_point;
# ifdef DEBUG
{
int i;
warning ("DEBUG: Switching to :");
for (i = 0; i <= argcnt; i++)
warning(" %w", ScmCC.stack->array[ScmCC.stack_top - 1 - i]);
}
} else {
warning ("DEBUG: Returning :");
warning(" %w", ScmPeek());
# endif
}
goto c_cont_loop;
} else if (ScmTypeOf (tmp) == ScmType (Continuation)) {
if (argcnt != 1)
error ("VM: call to escape procedure with argcnt = %u",
(unsigned) argcnt);
# ifdef DEBUG
warning ("DEBUG: Escaping...");
# endif
reverse_new = ScmPop ();
ScmSetContinuation (tmp);
ScmPush (reverse_new);
reverse_new = NULL;
goto c_cont_loop;
} else
error ("VM: call of non-procedure: %w", tmp);
break;
case CALL_AND_EXIT:
argcnt = cp [1];
/* incrementing nxt_stat is not necessary */
# ifdef DEBUG
{
int i;
warning ("DEBUG: Switching to :");
for (i = 0; i <= argcnt; i++)
warning(" %w", ScmCC.stack->array[ScmCC.stack_top - 1 - i]);
}
# endif
ScmRevertToFatherContinuation (argcnt + 1);
goto call_entry_point;
break;
case EXIT:
/* don't need to increment nxt_stat */
# ifdef DEBUG
warning ("DEBUG: Returning :");
warning(" %w", ScmPeek());
# endif
ScmRevertToFatherContinuation (1);
c_cont_loop:
while (ScmCC.code == NULL) {
ScmPrimitive *prim;
active_primitive = ScmCC.nxt_stat;
prim = GetScmPrimitive (active_primitive);
(* prim->cont) ();
active_primitive = SCM_VM_TRAP_CONT;
if (ScmCC.call_again > 0) {
argcnt = ScmCC.call_again - 1;
ScmCC.call_again = 0;
goto call_entry_point;
}
}
break;
case JUMP:
dist = cp [1];
ScmCC.nxt_stat += JUMP_len + dist;
break;
case JUMP_BACK:
dist = cp [1];
ScmCC.nxt_stat += JUMP_BACK_len;
ScmCC.nxt_stat -= dist;
break;
case POP_JUMP_IF_FALSE:
dist = cp [1];
if (ScmPop () == &ScmFalse)
ScmCC.nxt_stat += POP_JUMP_IF_FALSE_len + dist;
else
ScmCC.nxt_stat += POP_JUMP_IF_FALSE_len;
break;
case POP_JUMP_IF_TRUE:
dist = cp [1];
if (ScmPop () != &ScmFalse)
ScmCC.nxt_stat += POP_JUMP_IF_TRUE_len + dist;
else
ScmCC.nxt_stat += POP_JUMP_IF_TRUE_len;
break;
case JUMP_IF_FALSE_ELSE_POP:
dist = cp [1];
if (ScmPeek () == &ScmFalse)
ScmCC.nxt_stat += JUMP_IF_FALSE_ELSE_POP_len + dist;
else {
(void) ScmPop ();
ScmCC.nxt_stat += JUMP_IF_FALSE_ELSE_POP_len;
}
break;
case JUMP_IF_TRUE_ELSE_POP:
dist = cp [1];
if (ScmPeek () != &ScmFalse)
ScmCC.nxt_stat += JUMP_IF_TRUE_ELSE_POP_len + dist;
else {
(void) ScmPop ();
ScmCC.nxt_stat += JUMP_IF_TRUE_ELSE_POP_len;
}
break;
case JUMP_IF_FALSE_POP:
dist = cp [1];
if (ScmPeek () == &ScmFalse) {
(void) ScmPop ();
ScmCC.nxt_stat += JUMP_IF_FALSE_POP_len + dist;
} else
ScmCC.nxt_stat += JUMP_IF_FALSE_POP_len;
break;
case JUMP_IF_TRUE_POP:
dist = cp [1];
if (ScmPeek () != &ScmFalse) {
(void) ScmPop ();
ScmCC.nxt_stat += JUMP_IF_TRUE_POP_len + dist;
} else
ScmCC.nxt_stat += JUMP_IF_TRUE_POP_len;
break;
case LAMBDA:
con = cp [1];
proc = new (ScmType (Procedure));
proc->env = ScmCC.environ;
proc->code = ScmCC.constants->array [con];
ScmPush (proc);
ScmCC.nxt_stat += LAMBDA_len;
break;
case DELAY:
con = cp [1];
prom = new (ScmType (Promise));
prom->env = ScmCC.environ;
prom->code_or_value = ScmCC.constants->array [con];
ScmPush (prom);
ScmCC.nxt_stat += DELAY_len;
break;
case JUMP_IF_NOT_MEMV:
dist = cp [1];
con = cp [2];
if (ScmMemv (ScmPeek (), ScmCC.constants->array [con])
== &ScmFalse) {
ScmCC.nxt_stat += JUMP_IF_NOT_MEMV_len + dist;
} else {
(void) ScmPop ();
ScmCC.nxt_stat += JUMP_IF_NOT_MEMV_len;
}
break;
case CONS:
cons = new (ScmType (Cons));
cons->car = ScmPop ();
cons->cdr = ScmPeek ();
ScmSetTop (cons);
ScmCC.nxt_stat += CONS_len;
break;
case APPEND:
tmp = ScmPop ();
tmp = ScmAppendTwoLists (tmp, ScmPeek ());
ScmSetTop (tmp);
ScmCC.nxt_stat += APPEND_len;
break;
case LIST_TO_VECTOR:
ScmListToVector ();
ScmCC.nxt_stat += LIST_TO_VECTOR_len;
break;
case VECTOR:
siz = cp [1];
vect = NewScmVector (siz);
while (siz--)
vect->array [siz] = ScmPop ();
ScmPush (vect);
ScmCC.nxt_stat += VECTOR_len;
break;
case TAKE_TRUE:
ScmPush (&ScmTrue);
ScmCC.nxt_stat += TAKE_TRUE_len;
break;
case TAKE_FALSE:
ScmPush (&ScmFalse);
ScmCC.nxt_stat += TAKE_FALSE_len;
break;
case TAKE_NIL:
ScmPush (&ScmNil);
ScmCC.nxt_stat += TAKE_NIL_len;
break;
default:
error ("bad VM code: %i", (int) cp[0]);
break;
}
}
}
void ScmPushPrimitiveContinuation (void *environ, unsigned short stackreq)
{
assert (active_primitive != SCM_VM_TRAP_CONT);
reverse_old = environ;
ScmPushContinuation (stackreq);
ScmCC.environ = reverse_old;
ScmCC.nxt_stat = active_primitive;
reverse_old = NULL;
}
/*
* Scheme's assembly language
*/
static
unsigned short *label_address = NULL;
static
int label_count = 0;
static
void provide_n_labels (int n)
{
if (n > label_count) {
label_address = label_count == 0
? (unsigned short *) malloc (n * sizeof (unsigned short))
: (unsigned short *) realloc (label_address,
n * sizeof (unsigned short));
if (label_address == NULL) {
label_count = 0;
reset ("Out of memory");
}
label_count = n;
}
}
static
struct stat_desc *get_stat (void *opsym)
{
if (ScmTypeOf (opsym) == ScmType (Symbol))
return
find_stat (((ScmSymbol *) opsym)->array, ((ScmSymbol *) opsym)->length);
else if (ScmTypeOf (opsym) == ScmType (String))
return
find_stat (((ScmString *) opsym)->array, ((ScmString *) opsym)->length);
else
error ("vscm-asm: bad operation symbol: %w", opsym);
}
static
unsigned get_label_addresses (int nlabels, void *asmlist)
{
void *stat;
unsigned pc;
pc = 0;
provide_n_labels (nlabels);
while (ScmTypeOf (asmlist) == ScmType (Cons)) {
stat = ((ScmCons *) asmlist)->car;
asmlist = ((ScmCons *) asmlist)->cdr;
if (ScmTypeOf (stat) == ScmType (Cons))
pc += get_stat (((ScmCons *) stat)->car)->length;
else if (ScmTypeOf (stat) == ScmType (ExactNumber)) {
label_address [ScmNumberToInt (stat)] = pc;
} else
error ("vscm-asm: bad assembly code: %w -- %w", stat, asmlist);
}
return pc;
}
static void check_0 (void *x)
{
if (ScmTypeOf (x) != ScmType (Cons))
error ("check_0 failed: %w", x);
}
static void check_1 (void *x)
{
if (ScmTypeOf (x) != ScmType (Cons))
error ("check_1 failed: %w", x);
check_0 (((ScmCons *) x)->cdr);
}
static void check_2 (void *x)
{
if (ScmTypeOf (x) != ScmType (Cons))
error ("check_2 failed: %w", x);
check_1 (((ScmCons *) x)->cdr);
}
static unsigned short get_0 (void *x)
{
return ScmNumberToInt (((ScmCons *) x)->car);
}
static unsigned short get_1 (void *x)
{
return get_0 (((ScmCons *) x)->cdr);
}
static unsigned short get_2 (void *x)
{
return get_1 (((ScmCons *) x)->cdr);
}
static ScmCode *do_asm (void *, void *);
static
ScmCode *do_assembly (
unsigned short argcnt, int takerest, void *names, void *constants,
unsigned short stackreq, int nlabels, void *asmlist, void *nsym)
{
unsigned short length = get_label_addresses (nlabels, asmlist);
ScmCode *code;
unsigned nconstants = ScmListLength (constants);
ScmVector *cvect;
unsigned pc;
void *stat;
struct stat_desc *desc;
unsigned i;
unsigned short tmp;
constants_save = constants;
reverse_old = asmlist;
reverse_new = names;
append_save = nsym;
ScmPush (constants_save);
ScmPush (reverse_old);
reverse_old = NULL;
code = getmem (ScmType (Code),
sizeof (ScmCode) + (length - 1) * sizeof (unsigned short));
code->length = length;
code->arg_cnt = argcnt;
code->take_rest = takerest;
code->stack_requirement = stackreq;
code->argument_names = reverse_new;
code->proc_name = append_save;
append_save = reverse_new = NULL;
ScmPush (code);
cvect = NewScmVector (nconstants);
code = ScmPop ();
code->constants = cvect;
pc = 0;
for (asmlist = ScmPop (); ScmTypeOf (asmlist) == ScmType (Cons);
asmlist = ((ScmCons *) asmlist)->cdr) {
stat = ((ScmCons *) asmlist)->car;
if (ScmTypeOf (stat) == ScmType (Cons)) {
desc = get_stat (((ScmCons *) stat)->car);
code->array [pc] = desc->opcode;
switch (desc->opcode) {
case GET_LOC:
case GET_GLOB:
case PUT_LOC:
case PUT_GLOB:
case PUT_LOC_POP:
case PUT_GLOB_POP:
case TAKE:
case CALL:
case CALL_AND_EXIT:
case LAMBDA:
case DELAY:
case VECTOR:
check_1 (stat);
tmp = get_1 (stat);
code->array [pc + 1] = tmp;
break;
case JUMP:
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
case JUMP_IF_FALSE_ELSE_POP:
case JUMP_IF_TRUE_ELSE_POP:
case JUMP_IF_FALSE_POP:
case JUMP_IF_TRUE_POP:
check_1 (stat);
tmp = label_address [get_1 (stat)] - pc - desc->length;
code->array [pc + 1] = tmp;
break;
case JUMP_BACK:
check_1 (stat);
tmp = pc + desc->length - label_address [get_1 (stat)];
code->array [pc + 1] = tmp;
break;
case GET_ENV:
case PUT_ENV:
case PUT_ENV_POP:
case FRAME:
case FILL_FRAME:
check_2 (stat);
tmp = get_1 (stat);
code->array [pc + 1] = tmp;
tmp = get_2 (stat);
code->array [pc + 2] = tmp;
break;
case JUMP_IF_NOT_MEMV:
check_2 (stat);
tmp = label_address [get_1 (stat)] - pc - desc->length;
code->array [pc + 1] = tmp;
tmp = get_2 (stat);
code->array [pc + 2] = tmp;
break;
default:
/* do nothing */
break;
}
pc += desc->length;
}
}
constants_save = ScmPop ();
for (i = 0; i < nconstants; i++) {
stat = ((ScmCons *) constants_save)->car;
constants_save = ((ScmCons *) constants_save)->cdr;
if (ScmTypeOf (stat) != ScmType (Cons))
error ("vscm-asm: bad constant: %w", stat);
if (((ScmCons *) stat)->car == ScmQuotePtr) {
stat = ((ScmCons *) stat)->cdr;
if (ScmTypeOf (stat) != ScmType (Cons))
error ("vscm-asm: bad quotation: %w", stat);
else
code->constants->array [i] = ((ScmCons *) stat)->car;
} else {
append_save = code->proc_name;
ScmPush (code);
ScmPush (constants_save);
nsym = append_save;
append_save = NULL;
stat = do_asm (stat, nsym);
constants_save = ScmPop ();
code = ScmPop ();
code->constants->array [i] = stat;
}
}
constants_save = NULL;
return code;
}
static ScmCode *do_asm (void *stat, void *nsym)
{
unsigned short new_argcnt;
int new_takerest;
void *new_names;
void *new_constants;
unsigned int new_stackreq;
int new_nlabels;
check_0 (stat);
if (ScmTypeOf (((ScmCons *) stat)->car) == ScmType (String)) {
nsym = ((ScmCons *) stat)->car;
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
}
new_argcnt = get_0 (stat);
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
/* Since several Schemes write () for #f, we have to check for #t here */
new_takerest = (((ScmCons *) stat)->car == &ScmTrue ? 1 : 0);
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
new_names = ((ScmCons *) stat)->car;
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
new_constants = ((ScmCons *) stat)->car;
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
new_stackreq = get_0 (stat);
stat = ((ScmCons *) stat)->cdr;
check_0 (stat);
new_nlabels = get_0 (stat);
stat = ((ScmCons *) stat)->cdr;
return do_assembly (new_argcnt, new_takerest, new_names, new_constants,
new_stackreq, new_nlabels, stat, nsym);
}
void *ScmAsm (void *asmlist)
{
ScmCode *code = do_asm (asmlist, NULL);
ScmProcedure *proc;
ScmPush (code);
proc = new (ScmType (Procedure));
proc->code = ScmPop ();
proc->env = NULL;
return proc;
}
void *ScmAsmDcl (void *dcl)
{
ScmProcedure *proc;
ScmSymbol *sym;
if (ScmTypeOf (dcl) != ScmType (Cons))
fatal ("Atomic asm/dcl");
if (((ScmCons *) dcl)->car == ScmDefinePtr) {
dcl = ((ScmCons *) dcl)->cdr;
if (ScmListLength (dcl) != 2)
fatal ("Bad define for asm/dcl");
sym = ((ScmCons *) dcl)->car;
if (ScmTypeOf (sym) != ScmType (Symbol))
fatal ("asm/dcl: definition of non-symbol");
dcl = ((ScmCons *) ((ScmCons *) dcl)->cdr)->car;
if (ScmListLength (dcl) == 2 && ((ScmCons *) dcl)->car == ScmQuotePtr)
sym->value = ((ScmCons *) ((ScmCons *) dcl)->cdr)->car;
else {
ScmPush (sym);
ScmPush (do_asm (dcl, sym));
proc = new (ScmType (Procedure));
proc->env = NULL;
proc->code = ScmPop ();
sym = ScmPop();
sym->value = proc;
}
} else {
ScmPush (do_asm (dcl, NULL));
proc = new (ScmType (Procedure));
proc->env = NULL;
proc->code = ScmPop ();
return proc;
}
return NULL;
}